package com.bj58.ecdata.calc.dbservice.dao;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bj58.ecdata.calc.dbservice.dao.consts.DaoConst;
import com.bj58.ecdata.calc.dbservice.dao.model.DataPoint;
import com.bj58.ecdata.calc.dbservice.dao.model.FieldInfo;
import com.bj58.ecdata.exception.BusinessException;
import com.bj58.ecdata.util.ArithUtil;
import com.bj58.ecdata.util.DateUtils;
import com.bj58.ecdata.util.NumberUtils;
import com.google.common.collect.Lists;

/**
 * 封装了一些基本操作
 * @author lichao
 *
 */
public abstract class BaseDao<T> extends CacheBaseDao<T> {
	Logger log = LoggerFactory.getLogger(BaseDao.class);

	/**
	 * 保存一条记录
	 * @param model
	 */
	public void save(T model) {
		try {
			//写入mysql
			T obj = super.jdbc_insert(model);
			if (null != obj) {
				//写入redis
				this.cache_insert(model);
				this.setLatestPrimaryDimension(model);
			}
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}

	/**
	 * 修复小时数据
	 * 
	 * @param param
	 */
	public void fixHourlyData(T param) {
		try {
			List<T> models = super.jdbc_load(param);
			for (T model : models) {
				String primaryDimensionValue = super.primaryDimension.getReadMethod().invoke(model).toString();
				super.insertHourlyMultiDimensionMap(model, primaryDimensionValue);
			}
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}
	/**
	 * 修复分钟数据，从mysql导入redis
	 * @param param
	 */
	public void fixMinuteData(T param) {
		try {
			List<T> models = super.jdbc_load(param);
			for (T model : models) {
				String primaryDimensionValue = super.primaryDimension.getReadMethod().invoke(model).toString();
				super.insertMinuteMultiDimensionMap(model, primaryDimensionValue);
			}
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}

	/**
	 * 每日累计（带维度）
	 * 
	 * @param dimensionName
	 * @param model
	 * @return
	 */
	public long loadDailySum(String dimensionName, T model) {
		return super.cacheLoadDailyMultiDimensionValue(dimensionName, model);
	}

	/**
	 * 每日累计
	 * 
	 * @param dimensionName
	 * @return
	 */
	public long loadDailySum(String dimensionName) {
		return super.cacheLoadSumDimension(dimensionName);
	}

	private DataPoint createDataPoint(T model, long value, boolean div) throws Exception {
		long time = NumberUtils.toLong(super.primaryDimension.getReadMethod().invoke(model).toString());
		DataPoint data = new DataPoint();
		data.setTime(time);
		if (div) {
			data.setValue(ArithUtil.div(value, 100));
		} else {
			data.setValue(value);
		}
		return data;
	}

	public List<DataPoint> load(String type, List<T> models, boolean div) {
		try {
			List<DataPoint> result = Lists.newArrayList();
			for (T model : models) {
				long value = super.cacheLoadMultiDimensionValue(type, model);
				result.add(createDataPoint(model, value, div));
			}
			return result;
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}

	/**
	 * @param type
	 * @param models
	 *            维度
	 * @param div
	 * @return
	 */
	public List<DataPoint> loadMinute(String type, List<T> models, boolean div) {
		try {
			List<DataPoint> result = Lists.newArrayList();
			for (T model : models) {
				long value = super.cacheLoadMinuteMultiDimensionValue(type, model);
				result.add(createDataPoint(model, value, div));
			}
			return result;
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}

	/**
	 * 载入
	 * 
	 * @param type
	 * @param times
	 *            时间点
	 * @param div
	 * @return
	 */
	public List<DataPoint> loadMinuteByTime(String type, List<Long> times, boolean div) {
		try {
			List<DataPoint> result = Lists.newArrayList();
			for (long time : times) {
				long value = super.cacheLoadMinuteMultiDimensionValue(type, createModel(time));
				DataPoint data = new DataPoint();
				data.setTime(time);
				if (div) {
					data.setValue(ArithUtil.div(value, 100));
				} else {
					data.setValue(value);
				}
				result.add(data);
			}
			return result;
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}

	/**
	 * 从mysql中查询汇总 "时间点的前一分钟内的" 分钟级数据，
	 * @param type 指标
	 * @param times 时间点
	 * @param div是否除100
	 * @return
	 */
	public DataPoint loadMinuteFromMySQLByTime(String index, long time,Map<String, Object> params, boolean div) {
		try {
				long endTime = time + DaoConst._1m;
				String sql = createSQL(index,endTime, time,params,div);
				List<T> curList = super.jdbc_query(sql);
				if(curList.isEmpty()){
					curList.add(createModel(time));
				}
			
				T vo = curList.get(0);
				DataPoint data = new DataPoint();
				data.setTime(time);
				FieldInfo f = fieldInfos.get(index);
				data.setValue(f.getReadMethod().invoke(vo));
			return data;
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}

	private String createSQL(String index, long endTime, long time, Map<String, Object> params,boolean div) {
		String curTableName = String.format("%s_%s", this.tableName,DateUtils.dateFormat(time,"yyyyMMdd")); 
		
		StringBuilder sqlBuilder = new StringBuilder();
		sqlBuilder.append("select sum("+index+")");
		if(div){
			sqlBuilder.append("/100");
		}
		sqlBuilder.append(" as "+index+" from "); 
		sqlBuilder.append(curTableName);
		sqlBuilder.append(" where time>="+time+" and time<"+endTime);
		if(params!=null){
			for(String col : params.keySet()){
				sqlBuilder.append(" and "+col+"='"+params.get(col)+"'");
			}
		}
		return sqlBuilder.toString();
	}
	
	
	public List<DataPoint> loadHourly(String type, List<T> models, boolean div) {
		try {
			List<DataPoint> result = Lists.newArrayList();
			for (T model : models) {
				long value = super.cacheLoadHourlyMultiDimensionValue(type, model);
				result.add(createDataPoint(model, value, div));
			}
			return result;
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}

	public List<DataPoint> loadHourlyByTime(String type, List<Long> times, boolean div) {
		try {
			List<DataPoint> result = Lists.newArrayList();
			for (long time : times) {
				long value = super.cacheLoadHourlyMultiDimensionValue(type, createModel(time));
				DataPoint data = new DataPoint();
				data.setTime(time);
				if (div) {
					data.setValue(ArithUtil.div(value, 100));
				} else {
					data.setValue(value);
				}
				result.add(data);
			}
			return result;
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}

	/**
	 * 从mysql中查询汇总 "时间点的前一小时内的" 数据，
	 * @param type 指标
	 * @param times 时间点
	 * @param div是否除100
	 * @return
	 */
	public DataPoint loadHourlyFromMySQLByTime(String index, long time,Map<String, Object> params, boolean div) {
		try {
				long endTime = time + DaoConst._1h;
				String sql = createSQL(index,endTime, time,params,div);
				List<T> curList = super.jdbc_query(sql);
				if(curList.isEmpty()){
					curList.add(createModel(time));
				}
			
				T vo = curList.get(0);
				DataPoint data = new DataPoint();
				data.setTime(time);
				FieldInfo f = fieldInfos.get(index);
				data.setValue(f.getReadMethod().invoke(vo));
			return data;
		} catch (Exception e) {
			throw new BusinessException(e);
		}
	}
	
	public long getLatest() {
		return NumberUtils.toLong(super.getLatestPrimaryDimension()) - DaoConst._10s;
	}

	@Deprecated
	public int clearData(String sql) {
		sql = String.format(sql, super.tableName);
		return super.jdbc_update(sql, null);
	}

	public int clearData(Date date) {
		return super.dropTable(date);
	}
	
	public String getTableName() {
		return super.tableName;
	}

	public long delRedisKey(String key) {
		return super.cache.delete(key);
	}

	public T createModel(long time) {
		T model = null;
		try {
			model = super.entityClass.newInstance();
			super.primaryDimension.getWriteMethod().invoke(model, time);
		} catch (Exception e) {
			log.error("create model error!", e);
		}
		return model;
	}

}
